<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
    <head prefix="og: http://ogp.me/ns# article: http://ogp.me/ns/article#">
    <meta charset="UTF-8" />

    <meta name="generator" content="Hugo 0.69.2" /><meta name="theme-color" content="#fff" />
        <script>
            const userPrefers = localStorage.getItem('theme');
            const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
            const lightModeMediaQuery = window.matchMedia('(prefers-color-scheme: light)');
            if (userPrefers === 'dark') {
                changeModeMeta('dark');
            } else if (userPrefers === 'light') {
                changeModeMeta('light');
            } else if (darkModeMediaQuery.matches) {
                changeModeMeta('dark');
            } else if (lightModeMediaQuery.matches) {
                changeModeMeta('light');
            }
            function changeModeMeta(theme) {
                document.documentElement.setAttribute('data-theme', theme);
                if (theme === 'dark') {
                    changeThemeColor('#16171d');
                } else {
                    changeThemeColor('#fff');
                }
            }
            function changeThemeColor(themeColor) {
                document.querySelector('meta[name="theme-color"]').setAttribute('content', themeColor);
            }
        </script>

    

    
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    
    <meta name="format-detection" content="telephone=no, date=no, address=no, email=no" />
    
    <meta http-equiv="Cache-Control" content="no-transform" />
    
    <meta http-equiv="Cache-Control" content="no-siteapp" />

    <title>基于区块链技术的学历信息征信系统源码讲解 | SleepDevil</title>

    <link rel="stylesheet" href="../../css/meme.min.css" />

    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />

        <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=EB&#43;Garamond:ital,wght@0,400;0,500;0,700;1,400;1,700&amp;family=Noto&#43;Serif&#43;SC:wght@400;500;700&amp;family=Source&#43;Code&#43;Pro:ital,wght@0,400;0,700;1,400;1,700&amp;display=swap" media="print" onload="this.media='all'" />
        <noscript><link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=EB&#43;Garamond:ital,wght@0,400;0,500;0,700;1,400;1,700&amp;family=Noto&#43;Serif&#43;SC:wght@400;500;700&amp;family=Source&#43;Code&#43;Pro:ital,wght@0,400;0,700;1,400;1,700&amp;display=swap" /></noscript>

    <meta name="author" content="SleepDevil" />
    
    
    <meta name="description" content="最近在学习孔壹学院的基于区块链技术的学历信息征信系统项目，说实话代码其实看懂并不是很……" />

    <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon" />
    <link rel="mask-icon" href="../../icons/safari-pinned-tab.svg" color="#2a6df4" />
    <link rel="apple-touch-icon" sizes="180x180" href="../../icons/apple-touch-icon.png" />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="apple-mobile-web-app-title" content="SleepDevil" />
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
    <meta name="mobile-web-app-capable" content="yes" />
    <meta name="application-name" content="SleepDevil" />
    <meta name="msapplication-starturl" content="../../" />
    <meta name="msapplication-TileColor" content="#fff" />
    <meta name="msapplication-TileImage" content="../../icons/mstile-150x150.png" />
    <link rel="manifest" href="../../manifest.json" />

    
    

    
    <link rel="canonical" href="https://www.sunfangjie.com/blockchain-and-go/education-project/" />



<script type="application/ld+json">
    {
        "@context": "https://schema.org",
        "@type": "WebPage",
        "datePublished": "2020-08-25T15:38:12+08:00",
        "dateModified": "2020-08-27T16:25:45+08:00",
        "url": "https://www.sunfangjie.com/blockchain-and-go/education-project/",
        "name": "基于区块链技术的学历信息征信系统源码讲解",
        "description": "最近在学习孔壹学院的基于区块链技术的学历信息征信系统项目，说实话代码其实看懂并不是很……",
        "publisher": {
            "@type": "Organization",
            "name": "SleepDevil",
            "url": "https://www.sunfangjie.com/"
        },
        "mainEntityOfPage": {
            "@type": "WebSite",
            "@id": "https://www.sunfangjie.com/"
        }
    }
</script>

    



<meta name="twitter:card" content="summary" />

<meta name="twitter:site" content="@sleepdevil" />

    





<meta property="og:title" content="基于区块链技术的学历信息征信系统源码讲解" />
<meta property="og:description" content="最近在学习孔壹学院的基于区块链技术的学历信息征信系统项目，说实话代码其实看懂并不是很……" />
<meta property="og:url" content="https://www.sunfangjie.com/blockchain-and-go/education-project/" />
<meta property="og:site_name" content="SleepDevil" />
<meta property="og:locale" content="zh" /><meta property="og:type" content="website" />

        <link rel="preconnect" href="https://www.google-analytics.com" crossorigin />

        


    
    <script async src="https://www.googletagmanager.com/gtag/js?id="></script>
    <script>
        window.dataLayer = window.dataLayer || [];
        function gtag(){dataLayer.push(arguments);}
        gtag('js', new Date());

        gtag('config', '');
    </script>




    
</head>

    <body>
        <div class="container">
            
    <header class="header" data-scroll-header>
        
            <div class="header-wrapper">
                <div class="header-inner">
                    
    <div class="site-brand">
        
            <a href="../../" class="brand">SleepDevil</a>
        
    </div>

                    <nav class="nav">
    <ul class="menu" id="menu">
        
            
        
        
        
        
            
                <li class="menu-item"><a href="../../front-end/"><span class="menu-item-name">Front-end</span></a>
                </li>
            
        
            
                <li class="menu-item active"><a href="../../blockchain-and-go/"><span class="menu-item-name">BlockChain and go</span></a>
                </li>
            
        
            
                <li class="menu-item"><a href="../../technology/"><span class="menu-item-name">Technology</span></a>
                </li>
            
        
            
                <li class="menu-item"><a href="../../thinking/"><span class="menu-item-name">Thinking</span></a>
                </li>
            
        
            
                <li class="menu-item"><a href="../../links/"><span class="menu-item-name">Links</span></a>
                </li>
            
        
            
                <li class="menu-item"><a href="../../about/"><span class="menu-item-name">About</span></a>
                </li>
            
        
            
                
                    <li class="menu-item">
                        
    
        
            
        
        <div id="theme-switcher">🌞</div>
    


                    </li>
                
            
        
            
                
            
        
    </ul>
</nav>

                </div>
            </div>
            
    <input type="checkbox" id="nav-toggle" aria-hidden="true" />
    <label for="nav-toggle" class="nav-toggle"></label>
    <label for="nav-toggle" class="nav-curtain"></label>


        
    </header>




            
            
    <main class="main single" id="main">
    <div class="main-inner">

        <article class="content post" data-align="justify" data-type="blockchain-and-go" data-toc-num="true">

            <h1 class="post-title">基于区块链技术的学历信息征信系统源码讲解</h1>

            

            
                
            

            
                

<div class="post-meta">
    
        
        <time datetime="2020-08-25T15:38:12+08:00" class="post-meta-item published"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon post-meta-icon"><path d="M148 288h-40c-6.6 0-12-5.4-12-12v-40c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v40c0 6.6-5.4 12-12 12zm108-12v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 96v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm-96 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm192 0v-40c0-6.6-5.4-12-12-12h-40c-6.6 0-12 5.4-12 12v40c0 6.6 5.4 12 12 12h40c6.6 0 12-5.4 12-12zm96-260v352c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V112c0-26.5 21.5-48 48-48h48V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h128V12c0-6.6 5.4-12 12-12h40c6.6 0 12 5.4 12 12v52h48c26.5 0 48 21.5 48 48zm-48 346V160H48v298c0 3.3 2.7 6 6 6h340c3.3 0 6-2.7 6-6z"/></svg>&nbsp;2020.8.25</time>
    
    
        
        <time datetime="2020-08-27T16:25:45+08:00" class="post-meta-item modified"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon post-meta-icon"><path d="M400 64h-48V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H160V12c0-6.627-5.373-12-12-12h-40c-6.627 0-12 5.373-12 12v52H48C21.49 64 0 85.49 0 112v352c0 26.51 21.49 48 48 48h352c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm-6 400H54a6 6 0 0 1-6-6V160h352v298a6 6 0 0 1-6 6zm-52.849-200.65L198.842 404.519c-4.705 4.667-12.303 4.637-16.971-.068l-75.091-75.699c-4.667-4.705-4.637-12.303.068-16.971l22.719-22.536c4.705-4.667 12.303-4.637 16.97.069l44.104 44.461 111.072-110.181c4.705-4.667 12.303-4.637 16.971.068l22.536 22.718c4.667 4.705 4.636 12.303-.069 16.97z"/></svg>&nbsp;2020.8.27</time>
    
    
    
        
        
        
    
    
        
        <span class="post-meta-item wordcount"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon post-meta-icon"><path d="M497.9 142.1l-46.1 46.1c-4.7 4.7-12.3 4.7-17 0l-111-111c-4.7-4.7-4.7-12.3 0-17l46.1-46.1c18.7-18.7 49.1-18.7 67.9 0l60.1 60.1c18.8 18.7 18.8 49.1 0 67.9zM284.2 99.8L21.6 362.4.4 483.9c-2.9 16.4 11.4 30.6 27.8 27.8l121.5-21.3 262.6-262.6c4.7-4.7 4.7-12.3 0-17l-111-111c-4.8-4.7-12.4-4.7-17.1 0zM124.1 339.9c-5.5-5.5-5.5-14.3 0-19.8l154-154c5.5-5.5 14.3-5.5 19.8 0s5.5 14.3 0 19.8l-154 154c-5.5 5.5-14.3 5.5-19.8 0zM88 424h48v36.3l-64.5 11.3-31.1-31.1L51.7 376H88v48z"/></svg>&nbsp;7052</span>
    
    
        
        <span class="post-meta-item reading-time"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon post-meta-icon"><path d="M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zm0 448c-110.5 0-200-89.5-200-200S145.5 56 256 56s200 89.5 200 200-89.5 200-200 200zm61.8-104.4l-84.9-61.7c-3.1-2.3-4.9-5.9-4.9-9.7V116c0-6.6 5.4-12 12-12h32c6.6 0 12 5.4 12 12v141.7l66.8 48.6c5.4 3.9 6.5 11.4 2.6 16.8L334.6 349c-3.9 5.3-11.4 6.5-16.8 2.6z"/></svg>&nbsp;15&nbsp;分钟</span>
    
    
        
            
            <span class="post-meta-item busuanzi-page-pv" id="busuanzi_container_page_pv"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class="icon post-meta-icon"><path d="M288 144a110.94 110.94 0 0 0-31.24 5 55.4 55.4 0 0 1 7.24 27 56 56 0 0 1-56 56 55.4 55.4 0 0 1-27-7.24A111.71 111.71 0 1 0 288 144zm284.52 97.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400c-98.65 0-189.09-55-237.93-144C98.91 167 189.34 112 288 112s189.09 55 237.93 144C477.1 345 386.66 400 288 400z"/></svg>&nbsp;<span id="busuanzi_value_page_pv"></span></span>
        
    
</div>
            

            
                <nav class="contents">
  <h2 id="contents" class="contents-title">目录</h2><ol class="toc">
    <li><a id="contents:项目结构图" href="#项目结构图">项目结构图</a></li>
    <li><a id="contents:项目结构描述" href="#项目结构描述">项目结构描述</a>
      <ol>
        <li><a id="contents:chaincode" href="#chaincode">chaincode</a></li>
        <li><a id="contents:fixtures" href="#fixtures">fixtures</a></li>
        <li><a id="contents:img" href="#img">img</a></li>
        <li><a id="contents:sdkinit" href="#sdkinit">sdkInit</a></li>
        <li><a id="contents:web" href="#web">web</a></li>
        <li><a id="contents:maingo" href="#maingo">main.go</a></li>
      </ol>
    </li>
    <li><a id="contents:数据的传输过程" href="#数据的传输过程">数据的传输过程</a>
      <ol>
        <li><a id="contents:first" href="#first">First</a></li>
        <li><a id="contents:second" href="#second">Second</a></li>
        <li><a id="contents:finally" href="#finally">Finally</a></li>
      </ol>
    </li>
    <li><a id="contents:区块链中的数据不可篡改" href="#区块链中的数据不可篡改">区块链中的数据不可篡改</a></li>
    <li><a id="contents:结语" href="#结语">结语</a></li>
    <li><a id="contents:参考" href="#参考">参考</a></li>
  </ol>
</nav><div class="post-body"><p style="text-indent:0"><span class="drop-cap">最</span>近在学习孔壹学院的<a href="https://chaindesk.cn/witbook/11/221" target="_blank" rel="noopener">基于区块链技术的学历信息征信系统项目</a>，说实话代码其实看懂并不是很难，毕竟我本来就是搞前端的，对后端也有一定的理解。难其实是难在环境部署。<del>（对于我来说）</del></p>
<p>关于部署本文章就不多赘述了，这篇文章主要是对于源码的一个讲解。为了方便大家的访问，我已经将源码fork至<a href="https://gitee.com/SleepDevil/education" target="_blank" rel="noopener">gitee</a>，有需要的可以自行clone。</p>
<h2 id="项目结构图"><a href="#项目结构图" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:项目结构图" class="headings">项目结构图</a></h2>
<p>这是一个基于浏览器的区块链项目，采取的是MVC架构模式，M——Model（模型），V——View（视图），C——（Controller）。这里简单介绍一下MVC架构模式，View视图层就是用户所看到的界面，也就是前端工程师所干的事情。Model是数据层，也就是程序需要操作的数据或信息。在这两个中间的是Controller控制层，它负责根据用户从&quot;视图层&quot;输入的指令，选取&quot;数据层&quot;中的数据，然后对其进行相应的操作，产生最终结果；也就是进行业务逻辑的处理。</p>
<p><img src="https://i.loli.net/2020/08/25/lL2QWhsJgpKFzCo.jpg" alt="structure"></p>
<p><img src="https://i.loli.net/2020/08/25/HcIQKtaLSEvd5M6.png" alt="Snipaste_2020-08-25_15-49-59"></p>
<h2 id="项目结构描述"><a href="#项目结构描述" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:项目结构描述" class="headings">项目结构描述</a></h2>
<h3 id="chaincode"><a href="#chaincode" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:chaincode" class="headings">chaincode</a></h3>
<p>顾名思义，放置链码的文件夹。什么是链码？其实链码本质上就是区块链中新手一直搞不懂的智能合约。只不过在<code>Hyperledger Fabric</code>中它被称为<code>chaincode</code>（链码）。<code> Hyperledger Fabric</code>中链码一般分为系统链码和用户链码。系统链码是<code>Fabric</code>提供给我们用于Fabric 节点自身的处理逻辑, 包括系统配置、背书、校验等工作的。系统链码共有五种类型：<strong>配置系统链码(CSCC)</strong>、<strong>生命周期系统链码(LSCC)</strong>、<strong>查询系统链码(QSCC)</strong>、<strong>背书管理系统链码(ESCC)</strong>。具体作用可查询<a href="https://chaindesk.cn/witbook/11/116" target="_blank" rel="noopener">这里</a>。用户链码则是我们开发者根据业务的需求编写出来的，其本质就是一个个的函数，它们运行在链码容器中，通过 Fabric 提供的接口与账本状态进行交互。ChainCode要在区块链网络中运行，需要经过<strong>链码安装</strong>和<strong>链码实例化</strong>两个步骤。</p>
<ul>
<li>
<p>其中<code>eduStruct.go</code>文件中定义了一个名为<code>Education</code>和一个<code>HistoryItem</code>的结构体。其中struct Education就是一个人的学历信息，包括姓名、性别、省份证号、专业等等。</p>
</li>
<li>
<p><code>eduCC.go</code>文件主要调用了fabric提供的一些sdk，然后定义了一些函数，这些函数的功能有：根据身份证号查询信息、添加信息、修改信息等。</p>
</li>
<li>
<p><code>main.go</code>是对于这一个整个<code>chaincode</code>文件夹的总结，提供了<code>main</code>函数。熟悉<code>go</code>语言的同学应该都知道，每一个<code>go</code>源文件都是以一个<code>package somepackage</code>开头的。每一个<code>package</code>包含着多个<code>go</code>源文件，而这些源文件中，只能有一个<code>main</code>函数，这个函数是这个<code>package</code>生成可执行程序的入口点（基本类似于C语言中的main函数）。那让我们来看看这个main函数到底做了什么：</p>
<pre><code>func main(){
    err := shim.Start(new(EducationChaincode))
    if err != nil{
        fmt.Printf(&quot;启动EducationChaincode时发生错误: %s&quot;, err)
    }
}
</code></pre><p>其实很简单，调用了fabric-sdk的shim函数接口的<code>Start</code>方法，具体定义可在<a href="https://godoc.org/github.com/hyperledger/fabric-chaincode-go/shim#Start" target="_blank" rel="noopener">这里</a>查询。这个函数接收一个<code>ChainCode</code>对象并返回一个变量；当链码的启动失败时，它会返回一个错误对象否则返回<code>nil</code>。</p>
<p>那么定义于<code>eduCC.go</code>中的那些业务逻辑的函数何时会被调用呢？让我们跳转到<code>chaincode/main.go</code>中的<code>Invoke</code>函数。可以看到，这个函数接收的参数是一个<code>shim.ChaincodeStubInterface</code>类型的变量<code>stub</code>，这里要注意一下：</p>
<pre><code>func (t *EducationChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{
    return shim.Success(nil)
}
</code></pre><p>对Go语言了解的不够深的小伙伴们可能看不太懂这个函数到底哪个是参数了，<del>其实我一开始也没看懂</del>。经过Google，懂了。<code>func</code>关键字后紧跟的小括号里指明了这个<code>Init</code>函数时<code>EducationChaincode</code>这个类的方法，然后调用这个方法的对象以指针形式以参数t传入函数内，本质就是一个语法糖，这个t是一个自定义的参数，而不是传入的参数。可以从下面的<code>Invoke</code>函数中看到，会调用一系列的<code>t.somefunc</code>。这里的<code>somefunc</code>就是我们在<code>eduCC.go</code>里定义的那一系列函数（chaincode）啦！</p>
<p>讲到这里，还要再介绍一个知识（怕有的小伙伴不知道）：开发人员编写的链码中，必须要实现<code>Init</code>与<code>Invoke</code>两个方法。其中：</p>
<ul>
<li>**Init：**在链码实例化或升级时被调用, 完成初始化数据的工作。</li>
<li><strong>invoke</strong>：更新或查询提案事务中的分类帐本数据状态时，Invoke 方法被调用， 因此响应调用或查询的业务实现逻辑都需要在此方法中编写实现。</li>
</ul>
<p>这样大家应该就能理解的更透彻了。</p>
</li>
</ul>
<h3 id="fixtures"><a href="#fixtures" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:fixtures" class="headings">fixtures</a></h3>
<p>这个文件夹是生成区块链底层网络环境所需的，其本质就是启动多个docker容器。</p>
<ul>
<li><code>pull_images.sh</code>是一个bash脚本，用来pull所需docker镜像。</li>
<li><code>docker-compose.yml</code>是一个配置文件，通过这个文件，<code>docker-compose up</code>命令可以开启配置文件当中的docker容器，将up改为down则是关闭。</li>
<li>另外两个文件夹则是有关区块链加密的，具体可以自行查询资料。</li>
</ul>
<h3 id="img"><a href="#img" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:img" class="headings">img</a></h3>
<p>这个文件夹与本项目无关，是教程中用于辅助的图。项目中的图在<code>web</code>文件夹中的<code>static</code>目录下。</p>
<h3 id="sdkinit"><a href="#sdkinit" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:sdkinit" class="headings">sdkInit</a></h3>
<p>这个文件夹是用于将链码的安装以及实例化操作进行自动化，避免了每次启动项目都要在命令行中敲繁琐的代码。</p>
<ul>
<li><code>fabricInitInfo.go</code>可以看到，这个文件很简单，就简单的定义了一个<code>InitInfo</code>的结构体。该结构体定义了智能合约（chaincode）所创建的通道（channel）名称、组织名称、chaincodeID、username等。</li>
<li><code>start.go</code>这个文件可以看到它定义了三个函数，分别为：<code>SetupSDK</code>、<code>CreateChannel</code>、<code>InstallAndInstantiateCC</code>。它们的作用分别是初始化SDK、创建通道并将指定的Peers加入、安装和实例化智能合约（chaincode）并创建客户端实例。</li>
</ul>
<p>但是细心的你可能会发现了，这个package里并没有<code>main</code>函数，也就是说这些函数只是定义了，并没有执行，那么它们是在哪里执行的呢？聪明的你可能早就发现了，在项目的根目录中有一个名为<code>main.go</code>的文件，它——就是我们的答案了。</p>
<p>可以看到，在文件开头的import中有一个：<code>&quot;github.com/kongyixueyuan.com/education/sdkInit&quot;</code>，这就将这一整个文件夹都给引入进来了，它们在<code>main.go</code>中就会以<code>sdkInit</code>这个前缀名存在着。可以看到<code>main</code>函数的第一行：<code>initInfo := &amp;sdkInit.InitInfo{……}</code>就是初始化了一个InitInfo的结构体，该结构体的定义可以在<code>sdkInit/fabricInitInfo.go</code>中查看。随后你可以看见定义在<code>sdkInit/start.go</code>中的三个函数都依次被执行了。关于<code>sdkInit</code>这个文件夹的作用就讲到这里。</p>
<p>###service</p>
<p>这个文件夹是业务层，在业务层中，我们使用 <code>Fabric-SDK-Go</code> 提供的接口对象调用相应的 API 以实现对链码的访问，最终实现对分类账本中的状态进行操作。其实到了这里就有点类似于我们日常页面的开发了，前后端分离，这里就类似于后端的接口了。只不过这里的接口是通过调用sdk去通过访问链码来间接对数据进行修改。这样的好处就是通过了区块链进行数据的REST，保证了数据的真实、可靠。</p>
<ul>
<li><code>domain.go</code>该文件定义了三个结构体，两个函数。函数的作用分别是注册链码以及接受链码结果。</li>
<li><code>eduService.go</code>该文件封装了了一系列对于数据的操作的函数。调用时机的话请继续往下看。</li>
</ul>
<h3 id="web"><a href="#web" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:web" class="headings">web</a></h3>
<p>这个目录是用来构建前端页面以及路由的。首先来看根目录中的唯一一个文件：<code>webServer.go</code>。该文件就定义了一个方法：<code>WebStart</code>。</p>
<p><img src="https://i.loli.net/2020/08/25/MdaGOhJyP71If63.png" alt="Snipaste_2020-08-25_22-02-22" style="zoom:70%;" /></p>
<p>看到这里我相信一些有过全栈开发经验的小伙伴们已经懂了。这里我简单举两个例子来说一下吧。</p>
<ul>
<li>
<pre><code>http.HandleFunc(&quot;/&quot;, app.LoginView)
</code></pre><p>这段代码表明，当我们访问web服务的根目录（即HandleFunc函数的第一个参数<code>&quot;/&quot;</code>）时，调用<code>app.LoginView</code>这个方法；该方法的定义可于<code>web/controller/controllerHandler.go</code>中查找到（先不具体讲，到后面会具体讲）。</p>
</li>
<li>
<pre><code>http.HandleFunc(&quot;/addEdu&quot;, app.AddEdu)
</code></pre><p>这段代码表明，当我们访问<code>/addEdu</code>目录时（注意：这里是相对路由，完整的应该为：<code>localhost:9000/addEdu</code>），调用<code>app.AddEdu</code>这个方法。该方法同样可于<code>web/controller/controllerHandler.go</code>中查到。</p>
</li>
</ul>
<p>总结：<code>webServer.go</code>文件用来定义页面路由规则。</p>
<ul>
<li>
<p><code>controller</code>该目录下有四个go文件：</p>
<ul>
<li><code>controllerHandler.go</code>该文件定义了<code>webServer.go</code>中访问对于路由所调用的方法（函数）。</li>
<li><code>controllerResponse.go</code> 该文件主要实现对用户请求的响应，将响应结果返回给客户端浏览器。</li>
<li><code>userinfo.go</code>该文件定义了用户名和密码。</li>
<li><code>upload.go</code>该文件定义了上传文件的方法。</li>
</ul>
</li>
<li>
<p><code>static</code></p>
<ul>
<li>css——一些样式文件</li>
<li>fonts——页面所需字体</li>
<li>images——页面所需图片</li>
<li>js——引入了bootstrap和jquery两个js库，简化操作。</li>
</ul>
</li>
<li>
<p><code>tpl</code></p>
<p>html文件以及网站图标。</p>
</li>
</ul>
<h3 id="maingo"><a href="#maingo" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:maingo" class="headings">main.go</a></h3>
<p>最终，我们可以看到在文件夹根目录中有一个<code>main.go</code>文件，我们可以看一下它开头的import：</p>
<pre><code>import (
	&quot;os&quot;
	&quot;fmt&quot;
	&quot;encoding/json&quot;
	&quot;github.com/kongyixueyuan.com/education/sdkInit&quot;
	&quot;github.com/kongyixueyuan.com/education/service&quot;
	&quot;github.com/kongyixueyuan.com/education/web/controller&quot;
	&quot;github.com/kongyixueyuan.com/education/web&quot;
)
</code></pre><p>可以看到，该文件仅引用了一些基本的自带库，其余的都是我们已经解析过的代码。它对他们进行了一个结合，使整个项目的逻辑更加清晰，各部分的耦合性降低。有利于开发者后续的维护。</p>
<h2 id="数据的传输过程"><a href="#数据的传输过程" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:数据的传输过程" class="headings">数据的传输过程</a></h2>
<p>看完了上面的项目结构描述，相信你大体上已经明白了这个项目是如何搭建的了。不过你应该对于数据的传输还是不太了解，因为这个项目使用的是CouchDB作为StateDB进行数据的存储的，但是你会发现上面的代码没有一处涉及到了CouchDB。所以这里我再将数据是如何从一个go语言结构体传输到CouchDB进行保存的这个过程来讲述一下。</p>
<h3 id="first"><a href="#first" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:first" class="headings">First</a></h3>
<p>首先，让我们来回顾一下这个项目。我们会发现一共有三个地方对学历信息的增删改查接口进行了封装。它们分别位于：</p>
<ul>
<li><code>chaincode/eduCC.go</code></li>
<li><code>service/eduService.go</code></li>
<li><code>web/controller/controllerHandler.go</code></li>
</ul>
<p>这里要教大家一个小技巧，如何分别两个<code>go package</code>是否有依赖关系？看文件开头的<code>import</code>。如果一个文件引入了另一个文件，那么说明它们之间有依赖关系，则可以忽略引入外部文件的文件。也就是说我们直接看最原始的封装。如果我们仔细看了<code>web/controller/controllerHandler.go</code>的代码，我们可以发现：它引入了<code>service</code>这个package。接下来我们观察<code>controllerHandler.go</code>中封装的接口，例如：<code>func AddEdu</code>。我们可以看到，它先获取html表单中的数据，然后将数据传入到<code>app.Setup.SaveEdu()</code>这一个函数中。让我们来看看这个函数的定义在哪里。首先由函数定义可知，app是一个<code>*Application</code>类型变量，也就是<code>Application</code>这个Struct(结构体)的指针。那么<code>Application</code>是在哪里定义的呢？让我们打开<code>web/controller/userInfo.go</code>，可以看到：</p>
<pre><code>type Application struct {
	Setup *service.ServiceSetup
}
</code></pre><p>这个结构体中只有一个变量：<code>Setup</code>。而该变量又是<code>service.Service.Setup</code>结构体的指针。所以我们再次跳转到<code>service/domain.go</code>。可以看到：</p>
<pre><code>type ServiceSetup struct {
	ChaincodeID	string
	Client	*channel.Client
}
</code></pre><p>到了这里，我们就看到了<code>app *Application</code>的本质了：一个定义于<code>service/domain.go</code>中的<code>ServiceSetup</code>结构体的一个指针变量。</p>
<p>于是<code>app.Setup.SaveEdu()</code>这个函数的定义也就很容易找到了，它其实就是<code>ServiceSetup</code>结构体的一个类方法。定义可在<code>service/eduService.go</code>中找到。由此我们可以知道：定义于<code>web/controller/controllerHandler.go</code>中的对于数据的增删改查接口本质上是<code>service</code>中的。所以我们不再关注<code>web/controller</code>。</p>
<h3 id="second"><a href="#second" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:second" class="headings">Second</a></h3>
<p>接下来，我们打开<code>service/eduService.go</code>，还是分析<code>SaveEdu</code>这个方法。可以看到，该函数首先调用了<code>registerEvent</code>方法进行链码事件的注册；然后到了关键的地方：</p>
<pre><code>req := channel.Request{ChaincodeID: t.ChaincodeID, Fcn: &quot;addEdu&quot;, Args: [][]byte{b, []byte(eventID)}}
respone, err := t.Client.Execute(req)
</code></pre><p>首先调用了<code>channel.Request</code>方法，它指明了要调用的链码，以及链码内要Invoke的函数args，args是序列化的结果，序列化是自定义的，只要链码能够按相同的规则进行反序列化即可。我们可以看到，在上面有这样的一行代码：</p>
<pre><code>b, err := json.Marshal(edu)
</code></pre><p>这就是将传入到<code>SaveEdu</code>中的参数<code>edu</code>进行序列化，再传入到链码的方法<code>addEdu</code>中。</p>
<p>随后我们通过<code>Client.Execute(req)</code>使用通道客户端的<code>Execute</code>接口调用链码。</p>
<h3 id="finally"><a href="#finally" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:finally" class="headings">Finally</a></h3>
<p>在上一章节，我们可以的得知：<code>service/eduService.go</code>中定义的接口其本质并没有变，还是调用了别的地方的函数。可是为什么这个文件的<code>import</code>中并没有引入<code>chaincode</code>这个package呢？因为它们共处于一个区块链网络环境中，节点之间可以相互通信。当通过<code>channel.Request</code>并<code>Client.Execute</code>后，对应的chaincode就会被执行，peer节点就会进行背书。所以并不需要要引入对应的包，但是务必要保证函数名相同。我们还是从<code>SaveEdu</code>这个方法接着讲下去。</p>
<p>上一章中，我们知道它是调用了链码中的<code>addEdu</code>方法，所以我们跳转到<code>chaincode/eduCC.go</code>，这里我们可以看到<code>addEdu</code>方法，也就是定义于<code>web/controller</code>中的<code>AddEdu</code>方法的庐山真面目了。让我们简单看一下这个函数吧：</p>
<pre><code>func (t *EducationChaincode) addEdu(stub shim.ChaincodeStubInterface, args []string) peer.Response {

	var edu Education
	err := json.Unmarshal([]byte(args[0]), &amp;edu)

	// 查重: 身份证号码必须唯一
	_, exist := GetEduInfo(stub, edu.EntityID)
	if exist {
		return shim.Error(&quot;要添加的身份证号码已存在&quot;)
	}

	_, bl := PutEdu(stub, edu)

	err = stub.SetEvent(args[1], []byte{})

	return shim.Success([]byte(&quot;信息添加成功&quot;))
}
</code></pre><p>这里我将代码进行了一些简化，但是麻雀虽小，五脏俱全。该函数首先对传入进来的字节数组进行反序列化，然后对于所添加信息的校验唯一性；如果唯一，则执行<code>PutEdu()</code>这个方法。这个方法，就是数据写入到CouchDB的步骤了。该函数的定义在<code>addEdu</code>的上方。可以看到，该函数先将传进来的json数据进行序列化；序列化完成后就开始了写入数据，即<code>stub.PutState()</code>方法。该方法是Fabric提供的go-sdk中封装好的一个接口。这个函数本质就是在StateDB中添加或修改一条数据。因为这里我们的StateDB指定为了CouchDB，所以就会写入至我们启动好的CouchDB中。有关这些接口的使用方法，可以参考<a href="https://www.cnblogs.com/studyzy/p/7360733.html" target="_blank" rel="noopener">这篇文章</a></p>
<p>到了这里，一个添加信息的方法就被我们理解了。数据是如何从页面中的html表单，到后端的接口，再到业务层中的调用链码，再到链码中的对于CouchDB的操作，我们已经心中有数了。其他的方法本质都是一样的，读者可以自行查看源码。</p>
<h2 id="区块链中的数据不可篡改"><a href="#区块链中的数据不可篡改" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:区块链中的数据不可篡改" class="headings">区块链中的数据不可篡改</a></h2>
<p>上一次的周报中，老师对该项目发出了一个疑问：为什么学历信息可以修改，区块链中的数据不是不可以修改的吗？首先，区块链网络本身是有加密保护的，而且该加密算法为不可逆算法，这一步就阻隔了大部分的恶意攻击。因为对于数据的增删改查都是在区块链网络中进行的；当攻击者无法进入该网络，自然无法通过sql注入、xss共计等方法来进行数据的获取与篡改。其次，就算攻击者有天大的本事，破解了加密算法，进入到了区块链网络中，它能修改的也只是CouchDB即StateDB中的数据。这里再介绍一下<code>Hyperledger Fabric</code>中的一个核心概念：Ledger（账本）。</p>
<blockquote>
<p>In Hyperledger Fabric, a ledger consists of two distinct, though related, parts – a world state and a blockchain. Each of these represents a set of facts about a set of business objects.</p>
</blockquote>
<p>官网说：一个账本由两个彼此不同但却相互关联的部分组成：</p>
<ul>
<li>world state(世界状态)</li>
<li>blockchain(区块链)</li>
</ul>
<p>世界状态是什么呢？其实就是我们说的<code>StateDB</code>，也就是一个数据库，它存储了一组账本状态的<strong>当前值</strong>。世界状态可以经常改变，因为我们可以创建、更新、删除状态。</p>
<p>其次是区块链。它是一个记录了促成当前世界状态的所有改变的交易日志。交易被收集在附加到区块链的区块中，能帮助我们理解所有促成当前世界状态的改变的历史。区块链数据结构与世界状态相差甚远，因为一旦把数据写入区块链，就无法修改，它是<strong>不可篡改的</strong>。</p>
<p>一个账本是由区块链和世界状态组成，其中世界状态是由区块链决定的，我们也可以说世界状态是源自区块链的。</p>
<p>区块链中记录的是交易的日志，促成当前时间状态的改变的历史。其实就相当于CouchDB中的<code>_rev</code>字段一样（有关CouchDB，可以学习一下我的<a href="https://www.sunfangjie.com/technology/CouchDB-views/" target="_blank" rel="noopener">这篇文章</a>），它会记录下每一次变动并且保证该记录不可变。这样，就算黑客修改了我们世界状态（即数据库）中的数据，我们也可以知道他做了什么。因为当他修改数据时，区块链中就会生成不可变的记录。</p>
<p>如果想更深入的了解，可以前往<a href="https://hyperledger-fabric.readthedocs.io/en/latest/ledger/ledger.html" target="_blank" rel="noopener">官网</a>学习。</p>
<h2 id="结语"><a href="#结语" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:结语" class="headings">结语</a></h2>
<p>以上就是对于这个项目的源码分析了，如果还有什么疑问可以评论区留言或在<a href="https://www.sunfangjie.com/about/" target="_blank" rel="noopener">About</a>页面找到我的联系方式与我取得联系。如果这篇文章对你有所帮助，欢迎<a href="https://github.com/SleepDevil/sleepdevil.github.io" target="_blank" rel="noopener">Star</a></p>
<h2 id="参考"><a href="#参考" class="anchor-link"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon anchor-icon"><path d="M326.612 185.391c59.747 59.809 58.927 155.698.36 214.59-.11.12-.24.25-.36.37l-67.2 67.2c-59.27 59.27-155.699 59.262-214.96 0-59.27-59.26-59.27-155.7 0-214.96l37.106-37.106c9.84-9.84 26.786-3.3 27.294 10.606.648 17.722 3.826 35.527 9.69 52.721 1.986 5.822.567 12.262-3.783 16.612l-13.087 13.087c-28.026 28.026-28.905 73.66-1.155 101.96 28.024 28.579 74.086 28.749 102.325.51l67.2-67.19c28.191-28.191 28.073-73.757 0-101.83-3.701-3.694-7.429-6.564-10.341-8.569a16.037 16.037 0 0 1-6.947-12.606c-.396-10.567 3.348-21.456 11.698-29.806l21.054-21.055c5.521-5.521 14.182-6.199 20.584-1.731a152.482 152.482 0 0 1 20.522 17.197zM467.547 44.449c-59.261-59.262-155.69-59.27-214.96 0l-67.2 67.2c-.12.12-.25.25-.36.37-58.566 58.892-59.387 154.781.36 214.59a152.454 152.454 0 0 0 20.521 17.196c6.402 4.468 15.064 3.789 20.584-1.731l21.054-21.055c8.35-8.35 12.094-19.239 11.698-29.806a16.037 16.037 0 0 0-6.947-12.606c-2.912-2.005-6.64-4.875-10.341-8.569-28.073-28.073-28.191-73.639 0-101.83l67.2-67.19c28.239-28.239 74.3-28.069 102.325.51 27.75 28.3 26.872 73.934-1.155 101.96l-13.087 13.087c-4.35 4.35-5.769 10.79-3.783 16.612 5.864 17.194 9.042 34.999 9.69 52.721.509 13.906 17.454 20.446 27.294 10.606l37.106-37.106c59.271-59.259 59.271-155.699.001-214.959z"/></svg></a><a href="#contents:参考" class="headings">参考</a></h2>
<p><a href="https://chaindesk.cn/witbook/11/" target="_blank" rel="noopener">从0到1：Hyperledger Fabric开发精要</a></p>
<p><a href="https://hyperledger-fabric.readthedocs.io/en/release-2.2/" target="_blank" rel="noopener">Hyperledger Fabric docs</a></p>
</div>

        </article>

        

        
    
    
    



        

        

        
    
    

<div class="post-share">

        

        <div class="share-items">

            
                
                <div class="share-item twitter">
                    
                    <a href="https://twitter.com/share?url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;text=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;hashtags=&amp;via=sleepdevil" title="分享到「Twitter」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon twitter-icon"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg></a>
                </div>
            

            
                
                <div class="share-item facebook">
                    
                    <a href="https://www.facebook.com/sharer/sharer.php?u=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;hashtag=%23" title="分享到「Facebook」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon facebook-icon"><path d="M504 256C504 119 393 8 256 8S8 119 8 256c0 123.78 90.69 226.38 209.25 245V327.69h-63V256h63v-54.64c0-62.15 37-96.48 93.67-96.48 27.14 0 55.52 4.84 55.52 4.84v61h-31.28c-30.8 0-40.41 19.12-40.41 38.73V256h68.78l-11 71.69h-57.78V501C413.31 482.38 504 379.78 504 256z"/></svg></a>
                </div>
            

            
                
                <div class="share-item linkedin">
                    
                    <a href="https://www.linkedin.com/shareArticle?mini=true&amp;url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;title=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;summary=%e6%9c%80%e8%bf%91%e5%9c%a8%e5%ad%a6%e4%b9%a0%e5%ad%94%e5%a3%b9%e5%ad%a6%e9%99%a2%e7%9a%84%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e9%a1%b9%e7%9b%ae%ef%bc%8c%e8%af%b4%e5%ae%9e%e8%af%9d%e4%bb%a3%e7%a0%81%e5%85%b6%e5%ae%9e%e7%9c%8b%e6%87%82%e5%b9%b6%e4%b8%8d%e6%98%af%e5%be%88%e2%80%a6%e2%80%a6&amp;source=SleepDevil" title="分享到「LinkedIn」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon linkedin-icon"><path d="M416 32H31.9C14.3 32 0 46.5 0 64.3v383.4C0 465.5 14.3 480 31.9 480H416c17.6 0 32-14.5 32-32.3V64.3c0-17.8-14.4-32.3-32-32.3zM135.4 416H69V202.2h66.5V416zm-33.2-243c-21.3 0-38.5-17.3-38.5-38.5S80.9 96 102.2 96c21.2 0 38.5 17.3 38.5 38.5 0 21.3-17.2 38.5-38.5 38.5zm282.1 243h-66.4V312c0-24.8-.5-56.7-34.5-56.7-34.6 0-39.9 27-39.9 54.9V416h-66.4V202.2h63.7v29.2h.9c8.9-16.8 30.6-34.5 62.9-34.5 67.2 0 79.7 44.3 79.7 101.9V416z"/></svg></a>
                </div>
            

            
                
                <div class="share-item telegram">
                    
                    <a href="https://t.me/share/url?url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;text=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3" title="分享到「Telegram」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" class="icon telegram-icon"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm121.8 169.9l-40.7 191.8c-3 13.6-11.1 16.9-22.4 10.5l-62-45.7-29.9 28.8c-3.3 3.3-6.1 6.1-12.5 6.1l4.4-63.1 114.9-103.8c5-4.4-1.1-6.9-7.7-2.5l-142 89.4-61.2-19.1c-13.3-4.2-13.6-13.3 2.8-19.7l239.1-92.2c11.1-4 20.8 2.7 17.2 19.5z"/></svg></a>
                </div>
            

            
                
                <div class="share-item weibo">
                    
                    <a href="https://service.weibo.com/share/share.php?&amp;url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;title=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;pic=https://www.sunfangjie.com/&amp;searchPic=false" title="分享到「新浪微博」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon weibo-icon"><path d="M407 177.6c7.6-24-13.4-46.8-37.4-41.7-22 4.8-28.8-28.1-7.1-32.8 50.1-10.9 92.3 37.1 76.5 84.8-6.8 21.2-38.8 10.8-32-10.3zM214.8 446.7C108.5 446.7 0 395.3 0 310.4c0-44.3 28-95.4 76.3-143.7C176 67 279.5 65.8 249.9 161c-4 13.1 12.3 5.7 12.3 6 79.5-33.6 140.5-16.8 114 51.4-3.7 9.4 1.1 10.9 8.3 13.1 135.7 42.3 34.8 215.2-169.7 215.2zm143.7-146.3c-5.4-55.7-78.5-94-163.4-85.7-84.8 8.6-148.8 60.3-143.4 116s78.5 94 163.4 85.7c84.8-8.6 148.8-60.3 143.4-116zM347.9 35.1c-25.9 5.6-16.8 43.7 8.3 38.3 72.3-15.2 134.8 52.8 111.7 124-7.4 24.2 29.1 37 37.4 12 31.9-99.8-55.1-195.9-157.4-174.3zm-78.5 311c-17.1 38.8-66.8 60-109.1 46.3-40.8-13.1-58-53.4-40.3-89.7 17.7-35.4 63.1-55.4 103.4-45.1 42 10.8 63.1 50.2 46 88.5zm-86.3-30c-12.9-5.4-30 .3-38 12.9-8.3 12.9-4.3 28 8.6 34 13.1 6 30.8.3 39.1-12.9 8-13.1 3.7-28.3-9.7-34zm32.6-13.4c-5.1-1.7-11.4.6-14.3 5.4-2.9 5.1-1.4 10.6 3.7 12.9 5.1 2 11.7-.3 14.6-5.4 2.8-5.2 1.1-10.9-4-12.9z"/></svg></a>
                </div>
            

            
                
                <div class="share-item douban">
                    
                    <a href="https://www.douban.com/share/service?href=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;name=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;text=%e6%9c%80%e8%bf%91%e5%9c%a8%e5%ad%a6%e4%b9%a0%e5%ad%94%e5%a3%b9%e5%ad%a6%e9%99%a2%e7%9a%84%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e9%a1%b9%e7%9b%ae%ef%bc%8c%e8%af%b4%e5%ae%9e%e8%af%9d%e4%bb%a3%e7%a0%81%e5%85%b6%e5%ae%9e%e7%9c%8b%e6%87%82%e5%b9%b6%e4%b8%8d%e6%98%af%e5%be%88%e2%80%a6%e2%80%a6" title="分享到「豆瓣」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon douban-icon"><path d="M.643.92v2.412h22.714V.92H.643zm1.974 4.926v9.42h18.764v-9.42H2.617zm2.72 2.408H18.69v4.605H5.338V8.254zm1.657 7.412l-2.512.938c1.037 1.461 1.87 2.825 2.512 4.091H0v2.385h24v-2.385h-6.678c.818-1.176 1.589-2.543 2.303-4.091l-2.73-.938a29.952 29.952 0 01-2.479 5.03h-4.75c-.786-1.962-1.677-3.641-2.672-5.03Z"/></svg></a>
                </div>
            

            
                
                <div class="share-item qq">
                    
                    <a href="https://connect.qq.com/widget/shareqq/index.html?url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;title=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;summary=%e6%9c%80%e8%bf%91%e5%9c%a8%e5%ad%a6%e4%b9%a0%e5%ad%94%e5%a3%b9%e5%ad%a6%e9%99%a2%e7%9a%84%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e9%a1%b9%e7%9b%ae%ef%bc%8c%e8%af%b4%e5%ae%9e%e8%af%9d%e4%bb%a3%e7%a0%81%e5%85%b6%e5%ae%9e%e7%9c%8b%e6%87%82%e5%b9%b6%e4%b8%8d%e6%98%af%e5%be%88%e2%80%a6%e2%80%a6&amp;pics=https://www.sunfangjie.com/&amp;site=SleepDevil" title="分享到「QQ」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon qq-icon"><path d="M433.754 420.445c-11.526 1.393-44.86-52.741-44.86-52.741 0 31.345-16.136 72.247-51.051 101.786 16.842 5.192 54.843 19.167 45.803 34.421-7.316 12.343-125.51 7.881-159.632 4.037-34.122 3.844-152.316 8.306-159.632-4.037-9.045-15.25 28.918-29.214 45.783-34.415-34.92-29.539-51.059-70.445-51.059-101.792 0 0-33.334 54.134-44.859 52.741-5.37-.65-12.424-29.644 9.347-99.704 10.261-33.024 21.995-60.478 40.144-105.779C60.683 98.063 108.982.006 224 0c113.737.006 163.156 96.133 160.264 214.963 18.118 45.223 29.912 72.85 40.144 105.778 21.768 70.06 14.716 99.053 9.346 99.704z"/></svg></a>
                </div>
            

            
                
                <div class="share-item qzone">
                    
                    <a href="https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=https://www.sunfangjie.com/blockchain-and-go/education-project/&amp;title=%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e6%ba%90%e7%a0%81%e8%ae%b2%e8%a7%a3&amp;summary=%e6%9c%80%e8%bf%91%e5%9c%a8%e5%ad%a6%e4%b9%a0%e5%ad%94%e5%a3%b9%e5%ad%a6%e9%99%a2%e7%9a%84%e5%9f%ba%e4%ba%8e%e5%8c%ba%e5%9d%97%e9%93%be%e6%8a%80%e6%9c%af%e7%9a%84%e5%ad%a6%e5%8e%86%e4%bf%a1%e6%81%af%e5%be%81%e4%bf%a1%e7%b3%bb%e7%bb%9f%e9%a1%b9%e7%9b%ae%ef%bc%8c%e8%af%b4%e5%ae%9e%e8%af%9d%e4%bb%a3%e7%a0%81%e5%85%b6%e5%ae%9e%e7%9c%8b%e6%87%82%e5%b9%b6%e4%b8%8d%e6%98%af%e5%be%88%e2%80%a6%e2%80%a6&amp;pics=https://www.sunfangjie.com/&amp;site=SleepDevil" title="分享到「QQ 空间」" target="_blank" rel="noopener"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon qzone-icon"><path d="M23.985 9.202c-.032-.099-.127-.223-.334-.258-.207-.036-7.351-1.406-7.351-1.406s-.105-.022-.198-.07c-.092-.047-.127-.167-.127-.167S12.447.956 12.349.77C12.25.583 12.104.532 12 .532c-.104 0-.251.051-.349.238-.098.186-3.626 6.531-3.626 6.531s-.035.12-.128.167c-.092.047-.197.07-.197.07S.556 8.908.348 8.943c-.208.036-.302.16-.333.258a.477.477 0 0 0 .125.449l5.362 5.49s.072.08.119.172c.016.104.005.21.005.21s-1.189 7.242-1.22 7.45.075.369.159.43c.083.062.233.106.421.013.189-.093 6.812-3.261 6.812-3.261s.098-.044.201-.061c.103-.017.201.061.201.061s6.623 3.168 6.812 3.261c.188.094.338.049.421-.013a.463.463 0 0 0 .159-.43c-.021-.14-.93-5.677-.93-5.677.876-.54 1.425-1.039 1.849-1.747-2.594.969-6.006 1.717-9.415 1.866-.915.041-2.41.097-3.473-.015-.678-.071-1.17-.144-1.243-.438-.053-.215.054-.46.545-.831a2640.5 2640.5 0 0 1 2.861-2.155c1.285-.968 3.559-2.47 3.559-2.731 0-.285-2.144-.781-4.037-.781-1.945 0-2.275.132-2.811.168-.488.034-.769.005-.804-.138-.06-.248.183-.389.588-.568.709-.314 1.86-.594 1.984-.626.194-.052 3.082-.805 5.618-.535 1.318.14 3.244.668 3.244 1.276 0 .342-1.721 1.494-3.225 2.597-1.149.843-2.217 1.561-2.217 1.688 0 .342 3.533 1.241 6.689 1.01l.003-.022c.048-.092.119-.172.119-.172l5.362-5.49a.477.477 0 0 0 .127-.449z"/></svg></a>
                </div>
            

            
                
                <div class="share-item qrcode">
                    <div class="qrcode-container" title="通过「二维码」"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon qrcode-icon"><path d="M0 224h192V32H0v192zM64 96h64v64H64V96zm192-64v192h192V32H256zm128 128h-64V96h64v64zM0 480h192V288H0v192zm64-128h64v64H64v-64zm352-64h32v128h-96v-32h-32v96h-64V288h96v32h64v-32zm0 160h32v32h-32v-32zm-64 0h32v32h-32v-32z"/></svg><div id="qrcode-img"></div>
                    </div>
                    <script src="https://cdn.jsdelivr.net/npm/qrcode-generator@1.4.4/qrcode.min.js"></script>

<script>
    var typeNumber = 0;
    var errorCorrectionLevel = 'L';
    var qr = qrcode(typeNumber, errorCorrectionLevel);
    qr.addData('https:\/\/www.sunfangjie.com\/blockchain-and-go\/education-project\/');
    qr.make();
    document.getElementById('qrcode-img').innerHTML = qr.createImgTag();
</script>

                </div>
            

        </div>

    </div>




        
    
    


        
    


        

        

        

        
    



    </div>
</main>


            
    <div id="back-to-top" class="back-to-top">
        <a href="#"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon"><path d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"/></svg></a>
    </div>

            
    <footer id="footer" class="footer">
        <div class="footer-inner"><div class="site-info">©&nbsp;2020–2020&nbsp;<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon footer-icon"><path d="M462.3 62.6C407.5 15.9 326 24.3 275.7 76.2L256 96.5l-19.7-20.3C186.1 24.3 104.5 15.9 49.7 62.6c-62.8 53.6-66.1 149.8-9.9 207.9l193.5 199.8c12.5 12.9 32.8 12.9 45.3 0l193.5-199.8c56.3-58.1 53-154.3-9.8-207.9z"/></svg>&nbsp;SleepDevil</div><div class="site-copyright">在保留本文作者及本文链接的前提下，非商业用途随意转载分享。</div>
                <div class="busuanzi-site-uv-and-pv">
                    <span id="busuanzi_container_site_uv">本站访客数&nbsp;<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" class="icon busuanzi-site-uv"><path d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z"/></svg>&nbsp;<span id="busuanzi_value_site_uv"></span></span>&nbsp;|&nbsp;<span id="busuanzi_container_site_pv">本站访问量&nbsp;<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class="icon busuanzi-site-pv"><path d="M288 144a110.94 110.94 0 0 0-31.24 5 55.4 55.4 0 0 1 7.24 27 56 56 0 0 1-56 56 55.4 55.4 0 0 1-27-7.24A111.71 111.71 0 1 0 288 144zm284.52 97.4C518.29 135.59 410.93 64 288 64S57.68 135.64 3.48 241.41a32.35 32.35 0 0 0 0 29.19C57.71 376.41 165.07 448 288 448s230.32-71.64 284.52-177.41a32.35 32.35 0 0 0 0-29.19zM288 400c-98.65 0-189.09-55-237.93-144C98.91 167 189.34 112 288 112s189.09 55 237.93 144C477.1 345 386.66 400 288 400z"/></svg>&nbsp;<span id="busuanzi_value_site_pv"></span></span>
                </div>

            
    
        <ul class="socials"><li class="socials-item">
                    <a href="../../rss.xml" target="_blank" rel="external noopener" title="RSS"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon social-icon"><path d="M19.199 24C19.199 13.467 10.533 4.8 0 4.8V0c13.165 0 24 10.835 24 24h-4.801zM3.291 17.415c1.814 0 3.293 1.479 3.293 3.295 0 1.813-1.485 3.29-3.301 3.29C1.47 24 0 22.526 0 20.71s1.475-3.294 3.291-3.295zM15.909 24h-4.665c0-6.169-5.075-11.245-11.244-11.245V8.09c8.727 0 15.909 7.184 15.909 15.91z"/></svg></a>
                </li><li class="socials-item">
                    <a href="mailto:formersleepdevil@gmail.com" target="_blank" rel="external noopener" title="Email"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon social-icon"><path d="M464 64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V112c0-26.51-21.49-48-48-48zm0 48v40.805c-22.422 18.259-58.168 46.651-134.587 106.49-16.841 13.247-50.201 45.072-73.413 44.701-23.208.375-56.579-31.459-73.413-44.701C106.18 199.465 70.425 171.067 48 152.805V112h416zM48 400V214.398c22.914 18.251 55.409 43.862 104.938 82.646 21.857 17.205 60.134 55.186 103.062 54.955 42.717.231 80.509-37.199 103.053-54.947 49.528-38.783 82.032-64.401 104.947-82.653V400H48z"/></svg></a>
                </li><li class="socials-item">
                    <a href="https://github.com/SleepDevil" target="_blank" rel="external noopener" title="GitHub"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="icon social-icon"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></a>
                </li><li class="socials-item">
                    <a href="https://twitter.com/SleepDevil2" target="_blank" rel="external noopener" title="Twitter"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" class="icon social-icon"><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg></a>
                </li><li class="socials-item">
                    <a href="https://t.me" target="_blank" rel="external noopener" title="Telegram"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512" class="icon social-icon"><path d="M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm121.8 169.9l-40.7 191.8c-3 13.6-11.1 16.9-22.4 10.5l-62-45.7-29.9 28.8c-3.3 3.3-6.1 6.1-12.5 6.1l4.4-63.1 114.9-103.8c5-4.4-1.1-6.9-7.7-2.5l-142 89.4-61.2-19.1c-13.3-4.2-13.6-13.3 2.8-19.7l239.1-92.2c11.1-4 20.8 2.7 17.2 19.5z"/></svg></a>
                </li></ul>
    



            
        </div>
    </footer>


        </div>
        <script src="../../js/meme.min.js"></script>


    <script src="https://cdn.jsdelivr.net/gh/cferdinandi/smooth-scroll/dist/smooth-scroll.polyfills.min.js"></script>

<script>
    var scroll = new SmoothScroll('a[href*="#"]', {
        speedAsDuration: true,
        header: '[data-scroll-header]'
    });
</script>










    



    <script src="https://cdn.jsdelivr.net/npm/medium-zoom@latest/dist/medium-zoom.min.js"></script>

<script>
    mediumZoom(document.querySelectorAll('div.post-body img'), {
        background: 'hsla(var(--color-bg-h), var(--color-bg-s), var(--color-bg-l), 0.95)'
    })
</script>




    <script src="https://cdn.jsdelivr.net/npm/instant.page@3.0.0/instantpage.min.js" type="module" defer></script>







    
        <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    




    </body>
</html>
